import type mapboxgl from 'mapbox-gl'
import { nextTick, onMounted, onUnmounted, reactive } from 'vue'
import type { LngLat } from '@/geom/great-circle'
import { map } from '../core'

export interface MapPosition {
  cursor: LngLat
  zoom: number
  pitch: number
  bearing: number
}

export function useMapPosition(): MapPosition {
  const pos = reactive<MapPosition>({
    cursor: { lng: 0, lat: 0 },
    zoom: 0,
    pitch: 0,
    bearing: 0
  })

  function onCursor(evt: mapboxgl.MapMouseEvent) {
    const { lng, lat } = evt.lngLat
    pos.cursor.lng = lng
    pos.cursor.lat = lat
  }

  function onZoom(evt: mapboxgl.MapboxEvent) {
    pos.zoom = Math.floor(evt.target.getZoom() * 100) / 100
  }

  function onRotate(evt: mapboxgl.MapboxEvent) {
    pos.bearing = Math.floor(evt.target.getBearing() * 100) / 100
  }

  function onPitch(evt: mapboxgl.MapboxEvent) {
    pos.pitch = Math.floor(evt.target.getPitch() * 100) / 100
  }

  function update() {
    pos.zoom = Math.floor(map.getZoom() * 1000) / 1000
    pos.bearing = Math.floor(map.getBearing() * 100) / 100
    pos.pitch = Math.floor(map.getPitch() * 100) / 100
  }

  onMounted(() => {
    nextTick(() => {
      map.on('mousemove', onCursor)
      map.on('zoom', onZoom)
      map.on('pitch', onPitch)
      map.on('rotate', onRotate)
      update()
    })
  })

  onUnmounted(() => {
    map.off('mousemove', onCursor)
    map.off('zoom', onZoom)
    map.off('pitch', onPitch)
    map.off('rotate', onRotate)
  })
  return pos
}

export function mapZoomOut(dz: number) {
  const mz = map.getZoom()
  setMapZoom(mz - dz)
}

export function mapZoomIn(dz: number) {
  const mz = map.getZoom()
  setMapZoom(mz + dz)
}
export function setMapZoom(z: number) {
  if (z < 0 || z >= 25) {
    return
  }
  map.setZoom(z)
}

export function setMapCenter(center: LngLat) {
  map.setCenter(center)
}

export function setMapCenterIfNotContain(center: LngLat) {
  const b = map.getBounds()
  if (!b.contains(center)) {
    map.setCenter(center)
  }
}

export function setMapPitch(p: number) {
  map.setPitch(p)
}

export function setMapBearing(b: number) {
  map.setBearing(b)
}
